#include <stdio.h>
#include "type.h"

PROC proc[NPROC];
PROC *freeList;
PROC *readyQueue;
PROC *running;

#include "queue.c"


/************************************************
kfork creates a child process; returns child pid.
When schedule to run, child PROC resumes to body()
*************************************************/
int kfork(){
    int i;
    PROC *p = dequeue(&freeList);
    if(!p){
        printf("no more proc!\n");
        return -1;
    }

/* inittialize the new proc and its stack */

p->status = READY;
p->priority = 1;        //all PROCs priority si 1, expect P0
p->ppid = running->pid;

/************ new task initial stack contents ************
kstack contains: |retPC|eax|ebx|ecx|edx|ebp|esi|edi|eflag|
                     -1  -2  -3  -4  -5  -6  -7  -8  -9
**********************************************************/
for (i = 1; i < 10; i++){
    p->kstack[SSIZE-i] = 0;
}
p->kstack[SSIZE-1] = (int)body();//(int)body??????
p->ksp = &(p->kstack[SSIZE-9]);
enqueue(&readyQueue, p);
return p->pid;
}

int kexit(){
    running->status = FREE;
    running->priority = 0;
    enqueue(&freeList, running);
    printList("freeList", freeList);
    tswitch();
}

int do_kfork(){
   int child = kfork();
   if(child < 0){
       printf("kfork failed\n");
   } 
   else{
       printf("proc %d kforked a child = %d\n", running->pid, child);
       printList("readyQueue", readyQueue);
   }
   return child;
}

int do_switch(){
    tswitch();
}

int do_exit(){
    kexit();
}

int body(){
    int c;
    printf("proc %d starts from body()\n", running->pid);
    while(1){
        printf("********************************\n");
        printf("proc %d running: parent=%d\n", running->pid, running->pid);
        printf("enter a key [f|s|q] : ");
        c = getchar();getchar();
        switch (c)
        {
        case 'f':
            do_kfork();
            break;
        case 's':
            do_switch();
            break;
        case 'q':
            do_exit();
            break;      
        }
    }
}

int init(){
    int i;
    PROC *p;
    for(i=0; i < NPROC; i++){
        p = &proc[i];
        p->pid = i;
        p->status = FREE;
        p->priority = 0;
        p->next = p + 1;
    }
    proc[NPROC-1].next = 0;
    freeList = &proc[0];    //all PROCs in freeList
    readyQueue = 0;         //readyQueue = empty

    //create P0 as the initial running process
    p = running = dequeue(&freeList);
    p->status = READY;
    p->ppid = 0;
    printList("freeList", freeList);
    printf("init complete: P0 running\n");
}

int main(){
    printf("Welcome to the MT Multitasking System\n");
    init();
    kfork();
    while(1){
        printf("P0: switch process\n");
       if(readyQueue){
           tswitch();
        } 
    }
    return 0;
}

int scheduler(){
    printf("proc %d in scheduler()\n", running->pid);
    if(running->status == READY){
        enqueue(&readyQueue, running);
    }
    printList("readyQueue", readyQueue);
    running = dequeue(&readyQueue);
    printf("next running = %d\n", running->pid);
}